package com.nulldev.util.concurrency.threadIt.v4.emapi.extensions;

import java.util.List;
import java.util.Queue;
import java.util.concurrent.TimeUnit;

import com.nulldev.util.VariableAPI.ArrayUtils;
import com.nulldev.util.concurrency.threadIt.v4.emapi.ExecutionPreference;
import com.nulldev.util.concurrency.threadIt.v4.emapi.uft.Executable;

public interface ExtendedExecutor {
	/**
	 * TODO: - Rewrite me to renderIt! v0.1 standards. - Use
	 * ExecutorFeatureExtensions instead of ExecutorFeature - Align function
	 * implementations and stubs.
	 */

//	@Deprecated
//	public static enum ExecutorFeature {
//		/* Feature Sets. */
//		
//		EXECUTOR_SLOTS,
//		SUBMIT_ALL,
//		TASK_DRAIN,
//		EXECUTE_WITHIN,
//		NATIVE_BATCHING,
//		URGENT_DISPATCH,
//		PRIORITY_QUEUE,
//		AWAIT_IDLE,
//		EXECUTE_WITH_PREFERENCE,
//		EXECUTOR_IS_IDLE,
//		
//		/* FT 1.1  */
//		
//		CANCELABLE_TASKS,
//		SLAVE_TASKS,
//		
//		/* FT 1.2 */
//		
//		/* Workarounds. */
//		
//		WORKAROUND_REDIRECT_TO_NATIVE_BATCH,
//		
//		/* Misc. */
//		
//		BLANK
//	}

	/* Core */

	default void unsupported() {
		throw new UnsupportedOperationException("Missing executor support!");
	}

	default void unsupported(final ExecutorFeatureExtensions ext) {
		throw new UnsupportedOperationException("Missing executor support for " + ext + "!");
	}

	default int iunsupported(final ExecutorFeatureExtensions ext) {
		throw new UnsupportedOperationException("Missing executor support for " + ext + "!");
	}

	default boolean bunsupported(final ExecutorFeatureExtensions ext) {
		throw new UnsupportedOperationException("Missing executor support for " + ext + "!");
	}

	default void checkIfSupported(final ExecutorFeatureExtensions ext) {
		if (!supportsFeature(ext))
			throw new UnsupportedOperationException("Missing executor support for " + ext + "!");
	}

	public boolean supportsFeature(final ExecutorFeatureExtensions feature);

	public ExecutorFeatureExtensions[] supported();

	public void execute(final Runnable r);

	/* EEX_query_* */

	public default boolean executorSupportsBatching() {
		return ArrayUtils.contains(supported(), ExecutorFeatureExtensions.EEX_executor_native_batching)
				&& ArrayUtils.contains(supported(), ExecutorFeatureExtensions.EEX_query_batching_supported);
	}

	public default boolean executorSupportsSlotCount() {
		return ArrayUtils.contains(supported(), ExecutorFeatureExtensions.EEX_core_executor_slots)
				&& ArrayUtils.contains(supported(), ExecutorFeatureExtensions.EEX_query_slots_supported);
	}

	public default boolean executorIsIdle() {
		this.checkIfSupported(ExecutorFeatureExtensions.EEX_query_is_idle);
		return false;
	}

	/* EEX_query_thread_affinity_supported */

	public default boolean executorSupportsThreadAffinity() {
		this.checkIfSupported(ExecutorFeatureExtensions.EEX_query_thread_affinity_supported);
		return false;
	}

	public default boolean executorSupportsThreadPinning() {
		this.checkIfSupported(ExecutorFeatureExtensions.EEX_query_thread_affinity_supported);
		return false;
	}

	/* EEX_query_cpu_layout */

	public default boolean executorSupportsCPULayouts() {
		this.checkIfSupported(ExecutorFeatureExtensions.EEX_query_cpu_layout);
		return false;
	}

	public default ICPULayout getCPULayout() {
		return getCPULayout(-1);
	}

	public default ICPULayout getCPULayout(final int cpu_nr) {
		this.unsupported(ExecutorFeatureExtensions.EEX_query_cpu_layout);
		return null;
	}

	/* EEX_core_submit_all_tasks */

	public default void executor_submitAll(final List<Runnable> r) {
		this.unsupported(ExecutorFeatureExtensions.EEX_core_submit_all_tasks);
	}

	/* EEX_core_executor_slots */

	public default int executor_getFreeSlots() {
		return this.iunsupported(ExecutorFeatureExtensions.EEX_core_executor_slots);
	}

	/* EEX_core_drain_task_queue */

	public default void executor_drainTasks(final Queue<Runnable> async_queue, final int batchSize) {
		this.unsupported(ExecutorFeatureExtensions.EEX_core_drain_task_queue);
	}

	/* EEX_core_execute_within_time */

	public default void executeWithin(final Runnable r, final long amount, final TimeUnit unit) {
		this.unsupported(ExecutorFeatureExtensions.EEX_core_execute_within_time);
	}

	/* EEX_executor_native_batching */

	public default void batch(Runnable f) {
		this.unsupported(ExecutorFeatureExtensions.EEX_executor_native_batching);
	}

	public default void batchAll(Runnable[] r) {
		this.unsupported(ExecutorFeatureExtensions.EEX_executor_native_batching);
	}

	/* EEX_executor_await_idle */

	public default void awaitIdle() {
		this.unsupported(ExecutorFeatureExtensions.EEX_executor_await_idle);
	}

	/* EEX_executor_low_priority_threads */

	public default boolean supportsLPT() {
		this.checkIfSupported(ExecutorFeatureExtensions.EEX_executor_low_priority_threads);
		return false;
	}

	public default boolean isLPTActive() {
		this.checkIfSupported(ExecutorFeatureExtensions.EEX_executor_low_priority_threads);
		return false;
	}

	public default void setLPTActive(final boolean state) {
		this.unsupported(ExecutorFeatureExtensions.EEX_executor_low_priority_threads);
	}

	public default int[] getLPTs() {
		this.unsupported(ExecutorFeatureExtensions.EEX_executor_low_priority_threads);
		return null;
	}

	public default void submitLP(final Runnable r) {
		this.unsupported(ExecutorFeatureExtensions.EEX_executor_low_priority_threads);
	}

	public default void submitLP(final Executable<?> r) {
		this.unsupported(ExecutorFeatureExtensions.EEX_executor_low_priority_threads);
	}

	/* EEX_core_execute_with_preference */

	public default void execute(final Runnable r, final ExecutionPreference e) {
		this.unsupported(ExecutorFeatureExtensions.EEX_core_execute_with_preference);
	}

	/* EEX_extended_unwinder_debugging */

	public default void hookUnwinder(final IExecutorUnwinder unwinder) {
		this.unsupported(ExecutorFeatureExtensions.EEX_extended_unwinder_debugging);
	}

	/* EEX_executor_attemptable_submissions */

	public default boolean supportsAttemptableSubmissions() {
		return false;
	}

	public default boolean attempt_submit(final Runnable r) {
		this.execute(r);
		return true;
	}

	/* EEX_executor_attemptable_submissions2 */

	public default boolean supportsAttemptableSubmissions2() {
		return false;
	}

	public default <T> boolean attempt_submit2(final Executable<T> task) {
		if (task == null) {
			return false;
		}

		this.execute((Runnable) task);
		return true;
	}

	/* EEX_executor_attemptable_batch_submissions */

	public default boolean supportsAttemptableBatchSubmissions() {
		return false;
	}

	public default boolean attempt_batch(final Runnable r) {
		if (this.executorSupportsBatching()) {
			this.batch(r);
		} else {
			this.execute(r);
		}
		return true;
	}

	/* EEX_executor_attemptable_drain_submissions */

	public default boolean supportsAttemptableDrainSubmissions() {
		return false;
	}

	public default int attempt_drain(final Queue<Runnable> r, final int batch_size) {
		this.executor_drainTasks(r, batch_size);
		return batch_size;
	}

	/* EEX_query_executor_forking */

	public default boolean executorIsForking() {
		return false;
	}

	/* EEX_query_debug */

	public static enum EEXDebugQueryType {
		/* Threading */

		EEX_DEBUG_TOTAL_THREAD_COUNT,
		EEX_DEBUG_ACTIVE_THREAD_COUNT,

		/* LPT */

		EEX_DEBUG_LPT_ACTIVE,
		EEX_DEBUG_LPT_ACTIVE_THREAD_COUNT,
		EEX_DEBUG_LPT_TOTAL_THREAD_COUNT,

		/* Queueing */

		EEX_DEBUG_TASKS_IN_QUEUE,

		/* Tasks */

		EEX_DEBUG_ACTIVE_TASKS_STACK_TRACE,

		/* Executor-specific */

		EEX_DCTE_NON_STANDARD_BATCHING_CHAIN_SIZE,
	}

	public default Object debug_query(final EEXDebugQueryType type) {
		return null;
	}

	/* EEX_query_executor_large_batches */

	public default boolean executorAllowLargeBatches() {
		return false;
	}

	public default int executorPreferredBatchSize() {
		return this.iunsupported(ExecutorFeatureExtensions.EEX_query_executor_large_batches);
	}
}
